/*
 * SpinBotFactory.java
 *
 * Created on Jul 3, 2007, 2:35:26 PM
 *
 * Copyright (c) 2007 Daniel Gronau
 *
 * This file is part of KanjiTori.
 *
 * KanjiTori is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 3 of the License, or
 * (at your option) any later version.
 *
 * KanjiTori is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>
 *
 */

package kanjitori.graphics.bot;

import com.jme.animation.SpatialTransformer;
import com.jme.bounding.BoundingSphere;
import com.jme.math.FastMath;
import com.jme.math.Quaternion;
import com.jme.renderer.ColorRGBA;
import com.jme.scene.Controller;
import com.jme.scene.Node;
import com.jme.scene.shape.Cylinder;
import com.jme.scene.state.CullState;
import com.jme.scene.state.MaterialState;
import java.awt.AlphaComposite;
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.RenderingHints;
import java.awt.Shape;
import java.awt.font.FontRenderContext;
import java.awt.font.TextLayout;
import java.awt.geom.AffineTransform;
import java.awt.image.BufferedImage;
import java.util.HashMap;
import java.util.Map;
import kanjitori.util.GraphicUtil;
import kanjitori.util.Parameters;
import kanjitori.util.Cache;

/**
 *
 * @author DGronau
 */
public class SpinBotFactory implements BotFactory {
    
    private static final String MAT_COLOR = "matColor";
    private static final String CORPUS_IMAGE = "corpusImage";
    private static final String FONT = "font";
    private static final String TEXT_COLOR = "textColor";
    private static final String FADE_OUT_TIME = "fadeOutTime";
    private static final String SPIN_TIME = "spinTime";
    private final static String DARK_COLOR = "darkColor";
    private static final String OUTLINE = "outline";
    
    private ColorRGBA matColor = Cache.getColorRGBA(1, 1, 1, 0);
    private String corpusImage = "data/corpus.png";
    private Font font = Cache.getFont("Arial Unicode MS", Font.PLAIN, 40);
    private Color textColor = Color.ORANGE;
    private int fadeOutTime = 2;
    private int spinTime = 8;
    private Color darkColor = Cache.getColor(51, 51, 0);
    private boolean outline = true;
    
    public Bot get(String key) {
        return new SpinBot(key);
    }
    
    public void setParams(Map<String, String> map) {
        ColorRGBA tempMatColor = Parameters.getColorRGBA(map.get(MAT_COLOR));
        if (tempMatColor != null) {  matColor = tempMatColor; }
        
        String tempCorpusImage = map.get(CORPUS_IMAGE);
        if (tempCorpusImage != null) { corpusImage = tempCorpusImage; }
        
        Font tempFont = Parameters.getFont(map.get(FONT));
        if (tempFont != null) { font = tempFont; }
        
        Color tempTextColor = Parameters.getColor(map.get(TEXT_COLOR));
        if (tempTextColor != null) { textColor = tempTextColor; }
        
        Color tempDarkColor = Parameters.getColor(map.get(DARK_COLOR));
        if (tempDarkColor != null) { darkColor = tempDarkColor; }
        
        Boolean tempOutline = Parameters.getBoolean(map.get(OUTLINE));
        if (tempOutline != null) { outline = tempOutline; }
        
        Integer tempFadeOutTime = Parameters.getInt(map.get(FADE_OUT_TIME));
        if (tempFadeOutTime != null) { fadeOutTime = tempFadeOutTime; }
        
        Integer tempSpinTime = Parameters.getInt(map.get(SPIN_TIME));
        if (tempSpinTime != null) { spinTime = tempSpinTime; }
    }
    
    public Map<String, String> getParams() {
        Map<String, String> map = new HashMap<String, String>();
        map.put(MAT_COLOR, Cache.colorRgbaString(matColor));
        map.put(CORPUS_IMAGE, corpusImage);
        map.put(FONT, Cache.fontString(font));
        map.put(TEXT_COLOR, Cache.colorString(textColor));
        map.put(FADE_OUT_TIME, "" + fadeOutTime);
        map.put(SPIN_TIME, "" + spinTime);
        map.put(DARK_COLOR, Cache.colorString(darkColor));
        map.put(OUTLINE, "" + outline);
        return map;
    }
    
    private class SpinBot extends AbstractBot {
        
        private MaterialState ms;
        private SpatialTransformer st;
        
        /** Creates a new instance of SpinBot
         * @param value the word(s) which should be displayed
         */
        public SpinBot(String value) {
            super(value);
        }
        
        void init() {
            node = new Node("bot");
            Image img = getImage(value);
            
            Cylinder cyl = new Cylinder("cyl",2, 20, 0.5f, 0.5f);
            
            cyl.setRenderState(ms = GraphicUtil.getMaterialState(matColor));
            cyl.setRenderState(GraphicUtil.loadTexture(img));
            cyl.setRenderState(GraphicUtil.getCullState(CullState.CS_BACK));
            cyl.updateRenderState();
            cyl.setModelBound(new BoundingSphere());
            cyl.updateModelBound();
            node.attachChild(cyl);
            
            SpatialTransformer st = new SpatialTransformer(1);
            st.setObject(cyl, 0, -1);
            st.setRepeatType(Controller.RT_WRAP);
            cyl.addController(st);
            
            Quaternion x0=new Quaternion();
            x0.fromAngles(-FastMath.PI/2, 2*FastMath.PI, 0);
            st.setRotation(0, 0f, x0);
            Quaternion x180=new Quaternion();
            x180.fromAngles(-FastMath.PI/2, FastMath.PI, 0);
            st.setRotation(0, spinTime / 2, x180);
            Quaternion x360=new Quaternion();
            x360.fromAngles(-FastMath.PI/2, 0, 0);
            st.setRotation(0, spinTime, x360);
            
            st.setNewAnimationTimes(0, spinTime);
            st.setCurTime(0);
            st.interpolateMissing();
        }
        
        public void die() {
            
            node.getChild(0).setRenderState(GraphicUtil.getTransparence());
            node.setRenderQueueMode(display().getRenderer().QUEUE_TRANSPARENT);
            node.updateRenderState();
            
            node.addController(new Controller() {
                private float time = 0;
                public void update(float f) {
                    time += f;
                    ms.getDiffuse().a = (fadeOutTime - time) / 2;
                    if (time > fadeOutTime) {
                        GraphicUtil.removeControllers(node);
                        remove();
                        GraphicUtil.cleanTexture(node);
                    }
                }
            });
        }
        
        public Image getImage(String value) {
            int dx = 30;
            int dy = 55;
            
            Image image = Cache.getImage(corpusImage);
            
            BufferedImage bi = new BufferedImage(512, 80,BufferedImage.TYPE_INT_RGB);
            Graphics2D bg = (Graphics2D) bi.getGraphics();
            bg.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
                    RenderingHints.VALUE_ANTIALIAS_ON);
            //draw the background texture
            bg.drawImage(image, 0, 0, null);
            bg.drawImage(image, 256, 0, null);
            bg.setColor(textColor);
            bg.setFont(font);
            
            bg.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.9f));
            StringBuilder displaySB = new StringBuilder();
            value += "  ";
            displaySB.append(value);
            while (bg.getFontMetrics().stringWidth(displaySB.toString() + value) < 512) {
                displaySB.append(value);
            }
            bg.drawString(displaySB.toString(), dx, dy);
            if (outline) {
                bg.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 1f));
                bg.setStroke(new BasicStroke(1,
                        BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND));
                bg.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
                        RenderingHints.VALUE_ANTIALIAS_ON);
                bg.setColor(darkColor);
                
                FontRenderContext frc = bg.getFontRenderContext();
                TextLayout tl = new TextLayout(displaySB.toString(), font, frc);
                Shape shape = tl.getOutline(AffineTransform.getTranslateInstance(dx, dy));
                bg.draw(shape);
            }
            bg.dispose();
            return bi;
        }

    }
}
